"use client";

import React, { useState, useCallback } from "react";
import {
  ReactFlow,
  Controls,
  Background,
  addEdge,
  Node,
  OnConnect,
  useNodesState,
  useEdgesState,
  Connection,
  Panel,
  EdgeChange,
  useReactFlow,
  NodeChange,
} from "@xyflow/react";

import CvNode, { CvNodeData } from "@/components/workflow/cv-node";
import { Button } from "@/components/ui/button";
import { PanelRightClose } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import CvNodeDetail from "@/components/workflow/cv-node-detail";
import { useNodeExecuter } from "@/hooks/node-executor";
import { initialNodes, initialEdges, taskExternalData } from "@/lib/const";
import ModelMenu from "@/components/workflow/model-menu";
import { TaskType } from "@/lib/types";

const nodeTypes = {
  cvNode: CvNode,
};

export default function WorkflowPage() {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const { addNodes } = useReactFlow<Node<CvNodeData>>();
  const [selectedNode, setSelectedNode] = useState<Node<CvNodeData> | null>(
    null
  );
  const [isDrawerOpen, setIsDrawerOpen] = useState(false);

  const toggleDrawer = useCallback(() => {
    setIsDrawerOpen((prev) => {
      if (prev) {
        setSelectedNode(null);
      }
      return !prev;
    });
  }, []);

  const isValidConnection = useCallback(
    (connection: Connection) => {
      const targetNodeHasInput = edges.some(
        (edge) => edge.target === connection.target
      );
      const sourceNodeHasOutput = edges.some(
        (edge) =>
          edge.source === connection.source &&
          edge.sourceHandle === connection.sourceHandle
      );
      console.log("isValidConnection", targetNodeHasInput, sourceNodeHasOutput);
      return !targetNodeHasInput && !sourceNodeHasOutput;
    },
    [edges]
  );

  const handleEdgesChange = useCallback(
    (changes: EdgeChange[]) => {
      onEdgesChange(changes);
      changes.forEach((change) => {
        if (change.type === "remove") {
          const edgeToRemove = edges.find((edge) => edge.id === change.id);
          if (edgeToRemove) {
            setNodes((nds) =>
              nds.map((node) => {
                if (node.id === edgeToRemove.target) {
                  const newInputs = node.data.inputs.map((input) => ({
                    ...input,
                    reference: "",
                  }));
                  return { ...node, data: { ...node.data, inputs: newInputs } };
                }
                return node;
              })
            );
          }
        }
      });
    },
    [edges, setNodes, onEdgesChange]
  );

  const handleNodesChange = useCallback(
    (changes: NodeChange<Node<CvNodeData>>[]) => {
      onNodesChange(changes);
      changes.forEach((change) => {
        if (
          change.type === "remove" &&
          selectedNode &&
          change.id === selectedNode.id
        ) {
          toggleDrawer();
        }
      });
    },
    [onNodesChange, selectedNode, toggleDrawer]
  );

  const onConnect: OnConnect = useCallback(
    (connection) => {
      if (isValidConnection(connection)) {
        const newEdge = {
          ...connection,
          markerEnd: {
            type: "arrow",
            color: "hsl(var(--secondary-foreground))",
          },
          style: { strokeWidth: 2, stroke: "hsl(var(--secondary-foreground))" },
        };
        setEdges((eds) => addEdge(newEdge, eds));
      }
    },
    [setEdges, isValidConnection] // Added isValidConnection to dependencies
  );

  const onNodeClick = useCallback(
    (event: React.MouseEvent, node: Node<CvNodeData>) => {
      setSelectedNode(node);
      setIsDrawerOpen(true);
    },
    []
  );

  const { executeNode } = useNodeExecuter();
  const handleExecuteNode = (id: string) => {
    executeNode(id, { recursive: true });
  };

  const handleAddNode = (task: TaskType, model: string) => {
    const preNode = nodes[nodes.length - 1];
    const x = preNode ? preNode.position.x + 250 : 0;
    const y = preNode ? preNode.position.y + 200 : 0;
    addNodes({
      id: crypto.randomUUID(),
      type: "cvNode",
      position: { x, y },
      data: {
        task,
        modelName: model,
        inputs: taskExternalData[task]?.inputs || [],
        outputs: taskExternalData[task]?.outputs || [],
        status: "idle",
      },
    });
  };

  return (
    <div className="flex-1 relative my-2">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={handleNodesChange}
        onEdgesChange={handleEdgesChange} // 使用自定义的 handleEdgesChange
        onConnect={onConnect}
        nodeTypes={nodeTypes}
        onNodeClick={onNodeClick}
        fitView
        colorMode="dark"
      >
        <Controls />
        <Background bgColor="hsl(var(--background))" />
        <Panel position="bottom-center">
          <ModelMenu onClick={handleAddNode} />
        </Panel>
      </ReactFlow>
      {isDrawerOpen && selectedNode && (
        <Card className="absolute right-2 top-0 w-96 h-full overflow-y-auto rounded-lg">
          <CardHeader className="flex flex-row items-center justify-between">
            <CardTitle>节点详情</CardTitle>
            <Button variant="ghost" size="icon" onClick={toggleDrawer}>
              <PanelRightClose className="h-5 w-5" />
            </Button>
          </CardHeader>
          <CardContent>
            <CvNodeDetail id={selectedNode.id} onExecute={handleExecuteNode} />
          </CardContent>
        </Card>
      )}
    </div>
  );
}
